<?php

namespace App\Services\Pay\GuoTonXinYi;

use App\Exceptions\BizException;
use App\Models\CommonConfigs;
use App\Models\Store;
use App\Services\Store\StoreMchService;
use Illuminate\Support\Facades\Log;

class Config
{
    public const COMPANY = "GuoTonXinYi";

    public const  PRO_DOMAIN = "https://yyfsvxm.postar.cn";

    public const TEST_DOMAIN = "http://jghwucyshtgjcbrnxgwe.gtxygroup.com/testterpay";
    //机构号
    public const ORG_ID = "61000000339654";
    //商户号
    public const MCH_NO = "60000001044678";
    public const VERSION = "1.0.0";

    public const publicKey = "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA0jiB0sL2S94EG43kq3dKwC9pQhXMhMFMBTFOMLm85H50RngSQ4kuxaj0k3wubYN/gc9uIljXYijs+SSDxVKnpsDMBTmxO8G12zJURUJLrDxgFi2uX4yYHxnhYPRgdinBpmtmQhofsjRl4qozxu0TFH8aCvB4k1sVzW8F1tnvoA8TlosXskaf3Uac+t7MvN+8AfOMVUy2Z2eTZw9ugIIKLcQXJltAspxnqouBUf4bPE/TwaGFyxBdEIfayaR6eqtdrdXkuiPvPso4w0V39rDWkRQQoAKHDUjycnDAhso9lLGcAGKflThCcJGyzt6Sw8lmjTtpOzd+1S3qPkxuuvDhFwIDAQAB";

    //商户补贴活动明细
    public const queryActSubDetail = "/yyfsevr/addCust/queryActSubDetail";

    //开通业务查询
    public const  OpenBusinessQuery = "/yyfsevr/custConfig/openBusinessQuery";
    //虚拟机构号关联商户
    public const connectCust = "/yyfsevr/order/connectCust";
    //商户服务化配置信息配置
    public const config = "/yyfsevr/custConfig/config";
    //微信APPID配置
    public const appidConfig = "/yyfsevr/addCust/appidConfig";
    //配置微信支付目录
    public const wxPayConfig = "/yyfsevr/addCust/wxPayConfig";
    //查询商户微信开发配置
    public const  custWxAppidConfig = "/yyfsevr/addCust/custWxAppidConfig";
    //公众号查询
    public const  getWxInfo = "/yyfsevr/weChat/getWxInfo";
    //获取银联用户标识
    public const  getPaypalTag = "/yyfsevr/order/getPaypalTag";
    //B扫C前获取OPENID
    public const  openid = "/yyfsevr/order/openid";
    //统一下单接口（C扫B）
    public const pay = "/yyfsevr/order/pay";
    //商户主扫（B扫C）
    public const scanByMerchant = "/yyfsevr/order/scanByMerchant";
    //生成电子码
    public const getCodeUrl = "/yyfsevr/order/getCodeUrl";
    //交易查询接口
    public const orderQuery = "/yyfsevr/order/orderQuery";
    //当天交易查询接口
    public const tradeQuery = "/yyfsevr/order/tradeQuery";
    //历史交易查询接口
    public const batchOrderQuery = "/yyfsevr/order/batchOrderQuery";
    //退款接口
    public const refund = "/yyfsevr/order/refund";
    //退款查询
    public const refundQuery = "/yyfsevr/order/refundQuery";
    public const queryLimit = "/yyfsevr/drawcash/queryLimit";

    //计算签名
    public const EmbedUrl = "/yyfsevr/trans/preOrder/getMiniAppPayInfo";

    //进件接口
    public const addCustUpdateStatus = "/yyfsevr/addCust/updateStatus";
    //商户进件上传文件
    public const addCustUploadImg = "/yyfsevr/addCust/uploadImg";

    public const addCustUpdateCustAccount = "/yyfsevr/addCust/updateCustAccount";

    public const addCustUpdateCustRate = "/yyfsevr/addCust/updateCustRate";

    public const addCustMiniApply = "/yyfsevr/addCust/miniApply";

    public const addCustCommonApply = "/yyfsevr/addCust/commonApply";

    public const addCustGetResult = "/yyfsevr/addCust/getResult";

    public const addCustGetCustInfo = "/yyfsevr/addCust/getCustInfo";

    public const addCustGetBeneficiar = "/yyfsevr/addCust/getBeneficiar";


    //基础信息查询
    public const addCustGetArea = "/yyfsevr/addCust/getArea";

    public const addCustGetBankInfo = "/yyfsevr/addCust/getBankInfo";

    public const addCustGetBranchInfo = "/yyfsevr/addCust/getBranchInfo";

    public const addCustGetCity = "/yyfsevr/addCust/getCity";

    public const addCustGetProvince = "/yyfsevr/addCust/getProvince";


    public const addCustGetSecondMcc = "/yyfsevr/addCust/getSecondMcc";

    public const addCustGetTopMcc = "/yyfsevr/addCust/getTopMcc";

    public const addCustQueryInfoByCard = "/yyfsevr/addCust/queryInfoByCard";


    public const getPublicProvince = "/yyfsevr/addCust/getPublicProvince";
    public const getPublicCity = "/yyfsevr/addCust/getPublicCity";

    public const getReportInfo = "/yyfsevr/addCust/getReportInfo";

    //安心签
    public const anxinsignPerson = "/yyfsevr/anxinsign/person";

    public const anxinsignCompany = "/yyfsevr/anxinsign/company";

    public const anxinsignSendCode = "/yyfsevr/anxinsign/sendCode";

    public const anxinsignCheckCode = "/yyfsevr/anxinsign/checkCode";


    public static function getDomain(): string
    {
        $domain = Config::PRO_DOMAIN;
        if (env("APP_ENV") == "dev" || env("APP_ENV") == "local") {
            $domain = Config::TEST_DOMAIN;
        }
        return $domain;
    }

    public static function checkSign(array $data, string $sign, array $config = []): bool
    {
        ksort($data);
        $sb = '';
        foreach ($data as $key => $value) {
            if (is_array($value)) {
                $value = json_encode($value, JSON_UNESCAPED_UNICODE);
            }
            $sb .= $key . '=' . $value . '&';
        }
        // 移除最后一个 '&'
        $res = rtrim($sb, '&');
        // 计算 SHA-256 哈希
        $sha256 = hash('sha256', $res);
        $public_key = $config["public_key"] ?? self::publicKey;
        // 解密签名
        $decodeSha256 = self::decode($sign, $public_key);
        // 返回比较结果
        return $sha256 === $decodeSha256;
    }


    /**
     * 1、将所有传的参数（包括timeStamp和version，不含sign）拼接成一个字符串，拼接格式: key1=value1&key2=value2&key3=value3，其中 key1，key2，key3按字母ASCII值大小升序排序，如果value是一个JSON，则将value转为json字符串再拼接，比如key1=value1&key2=value2&key3={"key4":"value4","key5":"value5"}，key3中value的key可以不排序，但要保证顺序和传参时的顺序一致（若参数值为null，则不要拼接，如果是空字符串，则还是需要拼接）
     * 2、将上面拼接的字符串用sha256算法hash（注意：结果为小写字母，若是大写的，需转为小写），以交易查询接口为例，拼接后的字符串为
     */
    public static function getSign(array $data, string $public_key): string
    {
        if (empty($public_key)) {
            throw new BizException("公钥为空");
        }
        unset($data["sign"]);
        //先过滤参数为空的数据
        foreach ($data as $k => $v) {
            if (empty($v) && $v != "0") {
                unset($data[$k]);
            }
            if ($v === "") {
                unset($data[$k]);
            }
        }
        ksort($data);
        $str = "";
        foreach ($data as $k => $v) {
            if (is_array($v)) {
                $v = json_encode($v, JSON_UNESCAPED_UNICODE);
            }
            $str .= $k . "=" . $v . "&";
        }
        $str = rtrim($str, "&");
        Log::channel("gtxy")->info("sign_str", [
            "data" => $data,
            "str" => $str
        ]);
        //获取算法
        $sha256 = hash('sha256', $str);
        //在进行rsa
        $key_pem =
            "-----BEGIN PUBLIC KEY-----
" .
            chunk_split(
                $public_key,
                64,
                "
"
            ) .
            "-----END PUBLIC KEY-----";

        $publicKey = openssl_pkey_get_public($key_pem); //检测是否公钥
        openssl_public_encrypt($sha256, $sign, $publicKey); //公钥加密
        $sign = base64_encode($sign);
        return $sign;
    }

    public static function decode(string $sign, string $public_key): string
    {
        $RSA_DECRYPT_BLOCK_SIZE = 256;
        $sign = base64_decode($sign);
        $data = str_split($sign, $RSA_DECRYPT_BLOCK_SIZE);
        $key_pem =
            "-----BEGIN PUBLIC KEY-----
" .
            chunk_split(
                $public_key,
                64,
                "
"
            ) .
            "-----END PUBLIC KEY-----"; // 公钥
        $pubKey = openssl_pkey_get_public($key_pem);
        $result = "";
        foreach ($data as $block) {
            openssl_public_decrypt($block, $dataDecrypt, $pubKey);
            $result .= $dataDecrypt;
        }
        return $result;
    }

    public static function post(string $url, array $params): array
    {
        $ch = curl_init();

        $this_header = ["Content-Type: application/json; charset=utf-8"];

        curl_setopt($ch, CURLOPT_HTTPHEADER, $this_header);

        curl_setopt($ch, CURLOPT_URL, $url);

        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);

        curl_setopt(
            $ch,
            CURLOPT_USERAGENT,
            "Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)"
        );

        curl_setopt($ch, CURLOPT_TIMEOUT, 30);

        curl_setopt($ch, CURLOPT_POST, 1);

        curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));

        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //如果不加验证,就设false,商户自行处理

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);

        $output = curl_exec($ch);

        curl_close($ch);

        $array = json_decode($output, true);
        if (empty($array) || !is_array($array)) {
            throw new \RuntimeException("参数响应异常");
        }
        //转换成数组
        return $array;
    }


    /**
     * 使用 cURL 发送 GET 请求
     *
     * @param string $url 请求的URL
     * @param array $params 请求参数数组（可选）
     * @param array $headers 请求头数组（可选）
     * @return array 包含响应内容和HTTP状态码的数组
     */
    public static function get($url, $params = [], $headers = [])
    {
        // 如果有参数，拼接到URL上
        if (!empty($params)) {
            $queryString = http_build_query($params);
            $url .= (strpos($url, '?') === false) ? '?' : '&';
            $url .= $queryString;
        }
        // 初始化cURL
        $ch = curl_init();
        $this_header = ["Content-Type: application/x-www-form-urlencoded; charset=utf-8"];
        curl_setopt($ch, CURLOPT_HTTPHEADER, $this_header);
        // 设置cURL选项
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt(
            $ch,
            CURLOPT_USERAGENT,
            "Mozilla/5.0 (compatible; MSIE 5.01; Windows NT 5.0)"
        );
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // 返回响应而不是直接输出
        curl_setopt($ch, CURLOPT_HEADER, false); // 不包含响应头在输出中
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); //如果不加验证,就设false,商户自行处理

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
        // 如果有自定义请求头
        if (!empty($headers)) {
            curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
        }
        // 执行请求
        $output = curl_exec($ch);
        curl_close($ch);
        // 检查是否有错误
//        if (curl_errno($ch)) {
//            $error = curl_error($ch);
//            curl_close($ch);
//            throw new \RuntimeException($error);
//        }
        $array = json_decode($output, true);
        if (empty($array) || !is_array($array)) {
            throw new \RuntimeException("参数响应异常");
        }
        //转换成数组
        return $array;
    }


    public static function config(string $store_id, string $config_id, string $company = "gtxy"): array
    {
        $mchNo = StoreMchService::getMchNo($store_id, $company);
        if (empty($mchNo)) {
            $store = Store::query()->where("store_id", $store_id)->first();
            if (!empty($store->pid)) {
                $storeP_store_id = Store::query()->where("id", $store->pid)->value("store_id");
                $mchNo = StoreMchService::getMchNo($storeP_store_id, $company);
            }
        }
        if (empty($mchNo)) {
            throw new BizException("国通商户号不存在");
        }
        //获取配置
        $config = CommonConfigs::query()->where("company", "gtxy")->where("config_id", $config_id)->first();
        if (empty($config)) {
            $config = CommonConfigs::query()->where("company", "gtxy")->where("config_id", "1234")->first();
        }

        if (empty($config)) {
            throw new BizException("国通配置不存在");
        }

        return [
            trim($mchNo),
            $config
        ];

    }

}